package com.example.springbootschedule.common.aspect;

import com.example.springbootschedule.common.annotation.RedisJobLock;
import com.example.springbootschedule.common.config.TaskPoolConfig;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class RedisJobLockAspect {

    private static final String LOCK_VALUE = "locked";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TaskPoolConfig taskPool;

    @Around("execution(* *.*(..)) && @annotation(com.example.springbootschedule.common.annotation.RedisJobLock)")
    public void redisLockAround(ProceedingJoinPoint point) {
        taskPool.getCommonTaskPoolExecutor().execute(new Thread(() -> {
            RedisJobAdvice(point);
        }));
    }

    private void RedisJobAdvice(ProceedingJoinPoint point) {
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        try {
            RedisJobLock myAnnotation = method.getAnnotation(RedisJobLock.class);
            String lockKey = myAnnotation.lockKey();
            long expireTime = myAnnotation.expireTime();
            if (stringRedisTemplate.opsForValue().setIfAbsent(lockKey, LOCK_VALUE, expireTime, TimeUnit.SECONDS)) {
                point.proceed();
                return;
            }
            log.info("{},未获取锁！", lockKey);
        } catch (Throwable e) {
            log.error("method:{},运行错误！", method, e);
            throw new RuntimeException();
        }
    }

}
